use std::alloc::Layout;
use std::cell::Ref;
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use std::mem::{ManuallyDrop, MaybeUninit};
use std::ptr::{drop_in_place, NonNull};
use std::{mem, ptr};

/// rust内部的内存对齐机制
/// if len.i is the byte length of each member in a struct
/// N is the total bytes of a struct
/// 1.rust requires memory alignment to be N times greater than 2
/// 2.start point of a struct is divided by Max(len.i)
/// 3.the alignment value of which The offset of each member in the structure relative to the start address of the structure
/// should be multiple of Min(N,len.i)
/// 4.total length of the structure is multiple of Min(N,Max(len.i))
/// if repr(align(M)) is set ,N = Min(N.M)
#[repr(align(8))]
struct Align1 {
    b: u8,  //1/4
    a: u64, //8/8
    c: u16, //2/4
}
// ->
#[repr(align(8))]
struct AlignAfter {
    b: u8,  //a###
    c: u16, //cc##
    a: u64, //aaaaaaaa
}
/// 在自动对齐时还会默认优化成员的相对位置以达到最佳内存对齐

/// 如果强制成员顺序，不要求对齐，则部分成员（奇数位置）的引用将不能进行
#[repr(packed)]
struct RefTest {
    a: u8,
    b: u16, // b所处的相对位置时奇数位，不允许指针寻址访问
    c: u32, // c所处的相对位置时奇数位，不允许指针寻址访问
}

impl Default for RefTest {
    fn default() -> Self {
        RefTest { a: 0, b: 0, c: 0 }
    }
}

struct DropTest {}

impl Drop for DropTest {
    fn drop(&mut self) {
        println!("droptest dropped");
    }
}

#[test]
fn base_data_type_align_test() {
    /// rust中基本数据对齐位是系统指针大小，例如64位电脑就是8字节
    ///其中slice,str等使用双字节存储，一个数据指针一个数据长度，方便自动drop
    println!("{}", std::mem::size_of::<&str>()); // 16
    println!("{}", std::mem::align_of::<&str>()); // 8
    /// dynamic 数据类型使用双字节 ，一个数据指针，一个trait携带的函数指针偏移值vtable
    println!("{}", std::mem::size_of::<&dyn Drop>()); // 16
    println!("{}", std::mem::align_of::<&dyn Drop>()); // 8
    /// 一些特殊的rust中标记类，没有大小，对齐为最小对齐1
    println!("{:#?}", Layout::new::<PhantomData<()>>());
    let slice_ = &[1, 2,3];
    unsafe {
        // size_of_value用来获取动态类型的可变的大小个数
        println!("{}",mem::size_of_val(slice_));
    }
}

#[test]
fn align_test() {
    println!("{}", std::mem::size_of::<Align1>());
    println!("{}", std::mem::size_of::<RefTest>());
    // let test1 = RefTest::default();
    // println!("{}", &test1.c);

    let mut drop = ManuallyDrop::new(DropTest {});
    unsafe {
        std::mem::drop(drop);
        // ManuallyDrop::drop(&mut   drop);
    }
    let mut init_test = MaybeUninit::uninit();
    let x = init_test.write(1);
    *x = 2;
    println!("{:?}", x);
    unsafe {
        println!("{:?}", init_test.assume_init_drop());
    }

    let i = &[1, 2, 3, 4 as u8][0..];

    // println!("{}",std::mem::size_of_val(&(i as *const _)));

    println!("{}", std::mem::size_of::<*const ()>());
    unsafe {
        println!("{}", std::mem::size_of_val(&[1, 2, 3, 4 as usize][0..]));
    }
}
//##################################################################################################//
/// rust drop机制
/// 基本上所有的rust类型都实现了drop特性，除了ManuallyDrop
/// drop时机： 当对象完全脱离生命周期时
/// 1. 没有任何地方再使用此变量
/// 2. 函数移动传递，变量移动都不会触发drop
/// 3. 移动赋值时原变量也会触发drop
/// 本质上就是当前变量没有任何使用的余地后自动drop
/// 可以通过mem::read,write等不安全操作实现多所有权机制延续drop时机
#[derive(Debug)]
struct DropWrap<T: Sized + Display + Clone>(T);

impl<T: Sized + Display + Clone> Clone for DropWrap<T> {
    fn clone(&self) -> Self {
        DropWrap(self.0.clone())
    }
}

impl<T: Sized + Display + Clone> Drop for DropWrap<T> {
    fn drop(&mut self) {
        println!("{} is dropped!!!", self.0);
    }
}

#[test]
fn raw_point_test() {
    // 移动赋值时drop
    {
        let mut before = DropWrap("before".to_string());
        // before data is dropped immediately
        before = DropWrap("after".to_string());
    }
    // ManuallyDrop 延长生命周期
    unsafe {
        let mut before = DropWrap("before".to_string());
        let mut md_before = ManuallyDrop::new(before);
        // 此时不会触发before的drop
        ManuallyDrop::drop(&mut md_before);
        //必须手动调用drop才能触发man_drop的调用
    }

    /// rust所有权的转移实际上只是浅拷贝，在编译器层面做了非常多的严格限制
    /// inner_fn只是获取before浅拷贝，但是before在栈上的地址被编译器无效化->后面可以重新利用这些栈地址
    /// drop方法本质上和函数调用一样，但是会进一步把before栈地址的数据内容清理掉转化为无效空间
    /// 引用和指针本质上都是值类型，直接drop也只会清理掉指针的数据空间，并不会影响指针的指向的数据内容
    unsafe {
        fn inner_fn<T: Debug>(any: T) {
            println!("{:#?}", any);
        }
        let before = DropWrap("try".to_string());
        inner_fn(before); // 转移所有权并不会触发drop
        let test_drop = DropWrap("drop drop".to_string());
    }

    // ptr::read和write的理解
    /// 由于在rust设计本身要求&引用类型必须是内存安全且值是初始化的
    /// 但是想要实现在引用的条件下转移变量的所有权却非常麻烦
    /// 例：&A 我们想暂时获取到A
    /// 1: copy A -> empty;
    /// 2: 在mut前提下 replace B -> A
    /// 最终&A -> &B 而且返回原有的A值
    /// 但是在rust安全（除非A本身支持copy+clone）前提条件下1，2步骤只能实现其中一个（只有1会出现多所有权问题，只有2会出现无法获取原有值问题）
    ///
    /// ptr::read 可以在一定条件下读取A中的值（本质是浅拷贝有指针只拷贝指针，有变量就拷贝变量）但是原有的A变量需要手动管理声明周期避免多次drop
    /// ptr::write 可以对目标对象直接的所有权覆盖，一般用于对未初始化地址赋值，对read后的原有地址赋值
    /// 通过以上两个特性可以方便的实现replace, take效果
    unsafe {
        let mut a = DropWrap("A".to_string());
        let b = DropWrap("B".to_string());

        // let old_a = ptr::read(&a);
        // println!("a:{:p}, new_a:{:p}", &a, &old_a);// 两者地址不同
        // // mem::forget(a); // 防止a重复drop
        // ptr::write(&a as *const _ as *mut DropWrap<String>,b);//用b取代a
        // println!("{:?}",a); // 此时a是新的内容，不用担心和旧的old_a中内容有冲突导致重复drop
        // //实际上此时的a,b公用一个“B"的所有权，由于在编译器层面b已经认为被销毁了，存在所有权只有a拥有

        //以上内容等同于mem::replace
        let old_a = mem::replace(&mut a, b);
    }
}
